<?php 
namespace app\Pay\controller;
use think\Controller;
use think\Request;
use think\Env;
use app\cli\controller\Soc as Notify;
use app\pay\model\Order;
class Pay extends Controller
{
    // URL:http://47.108.65.56/pay/pay?player=927819&gold=100&paytype=bankwap
    public function index(){
        $channel_status = Env::get("channel_status");//获取支付通道状态
        if((bool)$channel_status == true){
            $notify = new Notify();
            $request = input('request.');
            //记录日志，接收的请求
            $str_req = arr_to_jsonstr($request);
            record_log($str_req, "pay_req");

        	//调整数据结构
            $data['cuid'] = isset($request['player']) ? $request['player'] : "";// 用户ID
            $data['total_fee'] = isset($request['gold']) ? $request['gold'] : "";// 订单金额
            $data['paytype'] = isset($request['paytype']) ? $request['paytype'] : "";// 支付方式

    		//记录日志，发起的请求
            $str_post = arr_to_jsonstr($data);
            record_log($str_post, "pay_post");
    		
            // 验证参数是否完整
            $k = array("cuid"=>"player", "total_fee"=>"gold", "paytype"=>"paytype");
            foreach ($data as $key => $value) {
                if(empty($value)){
                    $msg = array("fun"=>"pay_return", "status"=>101, "msg"=>"Error: Param ".$k[$key]." is undefined");
                    http_request($this -> get_host_url()."/cli/soc", $msg);// socket通知服务器
                    $this -> assign("data", $msg);
                    return $this -> fetch("index/pay_error");
                }
            }
            $data['remark'] = $data['cuid'];// 订单备注

            if($data['paytype'] == "bankwap"){
                return $this -> skyl($data); // 银联
            }

            if($data['paytype'] == "alipay"){
                return $this -> skal($data); // 支付宝
            }
            

            $msg = array("fun"=>"pay_return", "status"=>102,"msg"=>"不被支持的支付方式");
            http_request($this -> get_host_url()."/cli/soc", $msg);//发起通知
            $this -> assign("data", $msg);
            return $this -> fetch("index/pay_error");
        }
        return $this -> fetch("index/channel_error");
    }
    
//==========================================银联=========================================
    public function skyl($param){
        $time = time();

//return {"status":"success","pay_url":"http:\/\/xxx/Pay_Gm_h5.html?p=20181225171311105128"}
//{"status":"error","msg":"暂时无法连接支付服务器!","data":[]}
        // number_format()函数通过千位分组来格式化数字，语法：number_format(数字,小数位,小数点,千分符)
        $data['pay_amount'] = number_format($param['total_fee'], 2, '.', ''); // 金额，保留两位小数
        $data['pay_applydate'] = date("Y-m-d H:i:s"); // 订单日期
        $data['pay_bankcode'] = $this -> get_pay_conf("skyl", "pay_code");//"bankwap"; //$param['paytype'] 支付方式：bank - 网银直连, fastbank - 网银快捷, bankwap - 银联wap, alipay - 支付宝, tenpay - 财付通, weixin - 微信扫码, alipaywap - 支付宝wap, tenpaywap - 财付通wap, qqrcode - 手Q扫码, wxh5 - 微信wap, qqwallet - QQ钱包wap, gzhpay - 微信公众号
        $data['pay_callbackurl'] = $this -> get_host_url().'/pay/pay/sk_return';// 同步跳转接口
        $data['pay_memberid'] = $this -> get_pay_conf("skyl", "id"); // 商户号
        $data['pay_notifyurl'] = $this -> get_host_url().'/pay/pay/sk_yl_notify';// 异步通知接口
        $data['pay_orderid'] = date("YmdHis", $time).mt_rand(1000,9999); // 商户订单号
        $data['pay_md5sign'] = $this -> sk_get_yl_sign($data);// 签名
        
        

        // 以下参数不参与签名
        $data['pay_attach'] = isset($param['remark']) ? $param['remark'] : $param['cuid'];// 订单备注
        $data['pay_productname'] = "商品";// 商品名称


        $url = $this -> get_pay_conf("skyl", "pay_url");// 请求地址
        $str_data = arr_to_jsonstr($data);
        record_log($str_data, "skyl_request");// 记录请求记录
        $res = form_post($url, $data);// 发起请求
        //$res = http_request($url, $data);// 发起请求
        //$res = json_decode($res, true);// json字符串转为数组
        //if($res['status'] == 'success' && $res['pay_url'] != ''){
        //    if (strpos($res['pay_url'], 'form') > 0) {
        //        echo $res['pay_url'];
        //    }else{
        //        $this -> redirect($res['pay_url']);
        //    }
        //    return;
        //}else{
        //    echo "订单提交失败";
        //}
    }

    public function sk_get_yl_sign($param){
        ksort($param);
        //签名方式 pay_amount={value}&pay_applydate={value}&pay_bankcode=901&pay_callbackurl={value}&pay_memberid={value}&pay_notifyurl={value}&pay_orderid={value}&key={apikey}
        //pay_amount=1.00&pay_applydate=2019-07-22 18:12:18&pay_bankcode=902&pay_callbackurl={return_url}&pay_memberid=10050&pay_notifyurl={notify_url}&pay_orderid=201907221812187608&key=8jka8tp58l7q6533rsmjnqnwxbop03lb
        $token = $this -> get_pay_conf("skyl", "token");//秘钥
        $sign = '';
        $len = count($param);
        $i = 0;
        foreach($param as $key => $value){
            if($i == 0){
                $sign .= $key."=".$value;
            }else{
                $sign .= "&".$key."=".$value;
            }
            $i++;
        }
        return strtoupper(md5($sign."&key=".$token));
    }

    // 支付结果通知
    public function sk_yl_notify(){
        if(Request::instance()->isPost()){
            $pst = input("post.");
            $str = arr_to_jsonstr($pst);
            record_log($str, "skyl_notify");//记录回传信息
        
            $data['amount'] = isset($pst['amount']) ? $pst['amount'] : "";//交易金额
            $data['datetime'] = isset($pst['datetime']) ? $pst['datetime'] : "";//交易时间
            $data['memberid'] = isset($pst['memberid']) ? $pst['memberid'] : "";//商户号
            $data['orderid'] = isset($pst['orderid']) ? $pst['orderid'] : "";//商户订单号
            $data['returncode'] = isset($pst['returncode']) ? $pst['returncode'] : "";//订单状态，00-成功，其他-失败
            $data['transaction_id'] = isset($pst['transaction_id']) ? $pst['transaction_id'] : "";//交易流水号
            //amount={value}&datetime={value}&memberid={value}&orderid={value}&returncode={value}&transaction_id={value}&key={apikey}            
            $mysign = $this -> sk_get_yl_sign($data);//验证签名
            
            if($data['memberid'] != $this -> get_pay_conf("skyl", "id")){
                return 'memberid is wrong';
            }

            // 检查订单是否已存在
            $order = new Order();
            $check_order = $order -> check_order($data['orderid']);
            if($check_order){
                return 'OK';
            }

            // 以下参数不参与签名验证
            $data['attach'] = isset($pst['attach']) ? $pst['attach'] : "";//订单备注，确定平台是否有返回
            $sign = isset($pst['sign']) ? $pst['sign'] : "";// 平台返回的签名
            if($sign == $mysign){
                if($data['returncode'] === '00'){
                    $res_data = array(
                        "fun"=>"pay_return", 
                        "status"=> 200,
                        "player" => $data['attach'],//确定平台是否有返回
                        "gold" => $data['amount'],
                        "paytype" => "bankwap",
                        "sys_order" => $data['transaction_id'],
                        "user_order" => $data['orderid'],
                        "msg" => "充值成功",
                    );
                    http_request($this -> get_host_url()."/cli/soc", $res_data);//发出通知
                    return 'OK';
                } else {
                    $res_data = array(
                        "fun"=>"pay_return", 
                        "status"=> 104,
                        "player" => $data['attach'],//确定平台是否有返回
                        "gold" => $data['amount'],
                        "paytype" => "bankwap",
                        "sys_order" => $data['transaction_id'],
                        "user_order" => $data['orderid'],
                        "msg" => "平台充值失败",
                    );
                    http_request($this -> get_host_url()."/cli/soc", $res_data);//发出通知
                    return 'fail';
                }
            } else {
                $res_data = array(
                    "fun"=>"pay_return", 
                    "status"=> 103,
                    "player" => $data['attach'],//确定平台是否有返回
                    "gold" => $data['amount'],
                    "paytype" => "bankwap",
                    "sys_order" => $data['transaction_id'],
                    "user_order" => $data['orderid'],
                    "msg" => "签名验证失败，平台返回的签名与实际不符",
                );
                http_request($this -> get_host_url()."/cli/soc", $res_data);//发出通知
                return 'signerr';
            }
        }
    }


//-----------------------------------alipay--------------------
    public function skal($param){
        $time = time();
        $data['pay_amount'] = number_format($param['total_fee'], 2, '.', ''); // 金额，保留两位小数
        $data['pay_applydate'] = date("Y-m-d H:i:s"); // 订单日期
        $data['pay_bankcode'] = $this -> get_pay_conf("skal", "pay_code");//"bankwap"; //$param['paytype'] 支付方式：bank - 网银直连, fastbank - 网银快捷, bankwap - 银联wap, alipay - 支付宝, tenpay - 财付通, weixin - 微信扫码, alipaywap - 支付宝wap, tenpaywap - 财付通wap, qqrcode - 手Q扫码, wxh5 - 微信wap, qqwallet - QQ钱包wap, gzhpay - 微信公众号
        $data['pay_callbackurl'] = $this -> get_host_url().'/pay/pay/sk_return';// 同步跳转接口
        $data['pay_memberid'] = $this -> get_pay_conf("skal", "id"); // 商户号
        $data['pay_notifyurl'] = $this -> get_host_url().'/pay/pay/sk_al_notify';// 异步通知接口
        $data['pay_orderid'] = date("YmdHis", $time).mt_rand(1000,9999); // 商户订单号
        $data['pay_md5sign'] = $this -> sk_get_al_sign($data);// 签名

        // 以下参数不参与签名
        $data['pay_attach'] = isset($param['remark']) ? $param['remark'] : $param['cuid'];// 订单备注
        $data['pay_productname'] = "ali商品";// 商品名称

        $url = $this -> get_pay_conf("skal", "pay_url");// 请求地址
        $str_data = arr_to_jsonstr($data);
        record_log($str_data, "skal_request");// 记录请求记录
        form_post($url, $data);
        //$res = http_request($url, $data);// 发起请求
        //$res = json_decode($res, true);// json字符串转为数组
        //if($res['status'] == 'success' && $res['pay_url'] != ''){
        //    if (strpos($res['pay_url'], 'form') > 0) {
        //        echo $res['pay_url'];
        //    }else{
        //        $this -> redirect($res['pay_url']);
        //    }
        //    return;
        //}else{
        //    echo "订单提交失败";
        //}
    }
    public function sk_get_al_sign($param){
        ksort($param);
        //签名方式 pay_amount={value}&pay_applydate={value}&pay_bankcode=901&pay_callbackurl={value}&pay_memberid={value}&pay_notifyurl={value}&pay_orderid={value}&key={apikey}
        //pay_amount=1.00&pay_applydate=2019-07-22 18:12:18&pay_bankcode=902&pay_callbackurl={return_url}&pay_memberid=10050&pay_notifyurl={notify_url}&pay_orderid=201907221812187608&key=8jka8tp58l7q6533rsmjnqnwxbop03lb
        $token = $this -> get_pay_conf("skal", "token");//秘钥
        $sign = '';
        $len = count($param);
        $i = 0;
        foreach($param as $key => $value){
            if($i == 0){
                $sign .= $key."=".$value;
            }else{
                $sign .= "&".$key."=".$value;
            }
            $i++;
        }
        return strtoupper(md5($sign."&key=".$token));
    }
    public function sk_al_notify(){
        if(Request::instance()->isPost()){
            $pst = input("post.");
            $str = arr_to_jsonstr($pst);
            record_log($str, "skal_notify");//记录回传信息
        
            $data['amount'] = isset($pst['amount']) ? $pst['amount'] : "";//交易金额
            $data['datetime'] = isset($pst['datetime']) ? $pst['datetime'] : "";//交易时间
            $data['memberid'] = isset($pst['memberid']) ? $pst['memberid'] : "";//商户号
            $data['orderid'] = isset($pst['orderid']) ? $pst['orderid'] : "";//商户订单号
            $data['returncode'] = isset($pst['returncode']) ? $pst['returncode'] : "";//订单状态，00-成功，其他-失败
            $data['transaction_id'] = isset($pst['transaction_id']) ? $pst['transaction_id'] : "";//交易流水号
            //amount={value}&datetime={value}&memberid={value}&orderid={value}&returncode={value}&transaction_id={value}&key={apikey}            
            $mysign = $this -> sk_get_al_sign($data);//验证签名
            //验证商户号，不是自己的商户充值，一律抛弃
            if($data['memberid'] != $this -> get_pay_conf("skal", "id")){
                return 'memberid is wrong';
            }
            // 检查订单是否已存在
            $order = new Order();
            $check_order = $order -> check_order($data['orderid']);
            if($check_order){
                return 'OK';
            }
            
            // 以下参数不参与签名验证
            $data['attach'] = isset($pst['attach']) ? $pst['attach'] : "";//订单备注，确定平台是否有返回
            $sign = isset($pst['sign']) ? $pst['sign'] : "";// 平台返回的签名
            if($sign == $mysign){
                if($data['returncode'] === '00'){
                    $res_data = array(
                        "fun"=>"pay_return", 
                        "status"=> 200,
                        "player" => $data['attach'],//确定平台是否有返回
                        "gold" => $data['amount'],
                        "paytype" => "alipay",
                        "sys_order" => $data['transaction_id'],
                        "user_order" => $data['orderid'],
                        "msg" => "充值成功",
                    );
                    http_request($this -> get_host_url()."/cli/soc", $res_data);//发出通知
                    return 'OK';
                } else {
                    $res_data = array(
                        "fun"=>"pay_return", 
                        "status"=> 104,
                        "player" => $data['attach'],//确定平台是否有返回
                        "gold" => $data['amount'],
                        "paytype" => "alipay",
                        "sys_order" => $data['transaction_id'],
                        "user_order" => $data['orderid'],
                        "msg" => "平台充值失败",
                    );
                    http_request($this -> get_host_url()."/cli/soc", $res_data);//发出通知
                    return 'fail';
                }
            } else {
                $res_data = array(
                    "fun"=>"pay_return", 
                    "status"=> 103,
                    "player" => $data['attach'],//确定平台是否有返回
                    "gold" => $data['amount'],
                    "paytype" => "alipay",
                    "sys_order" => $data['transaction_id'],
                    "user_order" => $data['orderid'],
                    "msg" => "签名验证失败，平台返回的签名与实际不符",
                );
                http_request($this -> get_host_url()."/cli/soc", $res_data);//发出通知
                return 'signerr';
            }
        }
    }


//-----------------------------------common--------------------
    // 同步跳转
    public function sk_return(){
        $request = input("request.");

        $data['pay_memberid'] = $request['pay_memberid'];
        $data['amount'] = $request['amount'];
        $data['datetime'] = $request['datetime'];
        $data['orderid'] = $request['orderid'];
        $data['returncode'] = $request['returncode'];
        $data['transaction_id'] = $request['transaction_id'];
        $mysign = $this -> sk_get_sign($data);//用于验证服务器返回的sign是否正确
        // 以下参数不参与签名验证
        $data['pay_attach'] = $request['pay_attach'];
        $data['sign'] = $request['sign'];

        if($data['sign'] == $mysign){
            if($data['status'] == '1'){
                $res_data = array(
                    "status" => 1,
                    "msg" => "订单提交成功",
                    "orderno" => $data['orderid'],
                    "gold" => $data['amount'],
                );
            } else {
                $res_data = array(
                    "status" => 0,
                    "msg" => "订单提交失败",
                    "orderno" => "",
                    "gold" => "",
                );
            }
        }else{
            $res_data = array(
                "status" => 0,
                "msg" => "签名验证失败，请联系管理员...",
                "orderno" => "",
                "gold" => "",
            );
        }
        $this -> assign("data", $res_data);
        return $this -> fetch('index/sk_return');
    }
//====================================================================================
    // 取出接口配置信息
    public function get_pay_conf($type=null, $attr=null){
        $conf['server_address'] = "47.108.65.56";//data服务器地址
        // 银联
        $conf['skyl']['id'] = "10039";
        $conf['skyl']['token'] = "zqbyrx7tsue1v3v2qahttya8atu6uh47";
        $conf['skyl']['pay_url'] = "http://www.63zhifu.cn/Pay_Index.html";//订单提交网关地址
        $conf['skyl']['query_url'] = "http://pay.juzsoft.cn/Pay_Trade_query.html";//订单查询网关地址
        $conf['skyl']['pay_code'] = "924";
        // alipay to card
        $conf['skal']['id'] = "10039";
        $conf['skal']['token'] = "zqbyrx7tsue1v3v2qahttya8atu6uh47";
        $conf['skal']['pay_url'] = "http://www.63zhifu.cn/Pay_Index.html";
        $conf['skal']['query_url'] = "http://pay.juzsoft.cn/Pay_Trade_query.html";//订单查询网关地址
        $conf['skal']['pay_code'] = "929";

        if(!empty($type)){
            switch ($type) {
                case 'server_address':
                    $key = 'server_address';
                    break;
                case 'skyl':
                case 'skal':
                    $key = $type;
                    break;
                default:break;
            }
            if(!empty($attr)){
                return $conf[$key][$attr];
            }else{
                return $conf[$key];
            }
        }
        return false;
    }

    // 获取服务器地址
    public function get_host_url(){
        $vhost = $this -> get_pay_conf("server_address");//47.108.65.242
        $ssl = (!empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == 'on')||(isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && strtolower($_SERVER['HTTP_X_FORWARDED_PROTO']) == 'https') ? true : false;// 是http请求还是https请求
        $sp = strtolower($_SERVER['SERVER_PROTOCOL']);// 请求页面时通信协议的名称和版本
        // strpos(string, find, start) 函数查找字符串a在字符串b中第一次出现的位置
        // substr(string, start, length)
        $protocol = substr($sp, 0, strpos($sp, '/')) . (($ssl) ? 's' : '');// 构造请求类型
        $port  = $_SERVER['SERVER_PORT'];// 获取端口
        $port = ((!$ssl && $port=='80') || ($ssl && $port=='443')) ? '' : ':'.$port;
        $host = isset($_SERVER['HTTP_X_FORWARDED_HOST']) ? $_SERVER['HTTP_X_FORWARDED_HOST'] : isset($_SERVER['HTTP_HOST']) ? explode(':', $_SERVER['HTTP_HOST'])[0] : isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : $vhost;
        return $protocol . '://' . $host . $port;
    }
}